//! Copyright 2012 Virtium Technology, Inc.
//! All rights reserved
//!
#include "BoardHardware.h"
#include "StrLib.h"
#include "Config.h"
#include "Rtc.h"
#include "User.h"
#include "Counter.h"

#if defined (__FW_BUILD__)
extern "C"  {
#include "stm32f10x.h"
}
#endif

cSysTick cCounter::s_LedRedTick;
bool     cCounter::s_LedRedIsOn;
cSysTick cCounter::s_LedGreenTick;
bool     cCounter::s_LedGreenIsOn;
cSysTick cCounter::s_BeepTick;
bool     cCounter::s_BeepIsOn;

U16      cCounter::s_CardCount;

bool     cCounter::s_NeedCheckTimePoint;
U16      cCounter::s_pTimeZoneStart[cConfig::TIME_ZONE_MAX];
U16      cCounter::s_pTimeZoneEnd[cConfig::TIME_ZONE_MAX];
U16      cCounter::s_TimeZoneStatus;
U16      cCounter::s_TimeZoneStatusOld;

U8 cCounter::s_DpSetDv;
U8 cCounter::s_DpSetCh;
U8 cCounter::s_DpSetTr;
U8 cCounter::s_DpSetNg;

static const U8 Led7SegDecode[16] = {0x5F, 0x06, 0x9B, 0x8F, 0xC6, 0xCD, 0xDD, 0x07, 0xDF, 0xCF, 0xD7, 0xDC, 0x59, 0x9E, 0xD9, 0xD1};

void cCounter::InitReset()
{
#if defined (__FW_BUILD__)
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(GPIO0_PERIPH, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO0_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIO0_PORT, &GPIO_InitStructure);

    RCC_APB2PeriphClockCmd(GPIO1_PERIPH, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO1_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIO1_PORT, &GPIO_InitStructure);

    RCC_APB2PeriphClockCmd(GPIO2_PERIPH, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO2_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIO2_PORT, &GPIO_InitStructure);

    RCC_APB2PeriphClockCmd(GPIO3_PERIPH, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO3_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIO3_PORT, &GPIO_InitStructure);

    RCC_APB2PeriphClockCmd(GPIO4_PERIPH, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO4_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIO4_PORT, &GPIO_InitStructure);

#endif
    SR_CLK_0;
    SR_DATA_0;
    SR_STB_0;

#if 1
    SetCounter(0);
    SetBeep(true);
    U32 cnt = 3000000;
    while (--cnt);
    SetBeep(false);

    U16 counterCnt = 0;
    bool toggleLed = false;
    for (U8 i=0; i<10; i++)
    {
        SetCounter(counterCnt);
        if (false == toggleLed)
        {
            SetLedRed(true);
            SetLedGreen(false);
            toggleLed = true;
        }
        else
        {
            SetLedRed(false);
            SetLedGreen(true);
            toggleLed = false;
        }
        cnt = 3000000;
        while (--cnt);
        counterCnt += 1111;
    }
#endif
    SetLedRed(false);
    SetLedGreen(false);
    SetBeep(false);

    U8 *pStrTime;
    U32 currMinute;
    pStrTime = cRtc::GetTimeAsStr();
    currMinute = pStrTime[3]*60 + pStrTime[4];
    UpdateTimeZone(currMinute);
    s_TimeZoneStatusOld = s_TimeZoneStatus;
    cUser::ResetUserReadMark();
}

void cCounter::LoadConfig()
{
#if TEST_MODE
    SetLedOffTime(1);
#else
    SetLedOffTime(cConfig::GetLedTimeOn());
#endif
    s_BeepTick.SetTimeout(1500);
    SetCounter(0000);
    cConfig::GetTimeZone(s_pTimeZoneStart, s_pTimeZoneEnd);
    s_NeedCheckTimePoint = false;
    s_DpSetDv = DP_LED_CLR;
    s_DpSetCh = DP_LED_CLR;
    s_DpSetTr = DP_LED_CLR;
    s_DpSetNg = DP_LED_CLR;
    UpdateCounter();
}


void cCounter::SetLedOffTime(U8 iSecond)
{
    s_LedRedTick.SetTimeout(iSecond * 1000);
    s_LedGreenTick.SetTimeout(iSecond * 1000);
    cConfig::SetLedTimeOn(iSecond);
}


void cCounter::SetLedRed(bool on)
{
    if (true == on) 
    {
        LED_RED_ON;
        s_LedRedTick.ResetTimeBase();
        s_LedRedIsOn = true;
    }
    else 
    {
        LED_RED_OFF;
        s_LedRedIsOn = false;
    }
}

void cCounter::SetLedGreen(bool on)
{
    if (true == on) 
    {
        LED_GREEN_ON;
        s_LedGreenTick.ResetTimeBase();
        s_LedGreenIsOn = true;
    }
    else 
    {
        LED_GREEN_OFF;
        s_LedGreenIsOn = false;
    }
}


void cCounter::ShiftLed(U8 iData)
{
    U8 i = 7;
    while (0xFF > i)
    {
        (0 < (iData & (1<<i)))? SR_DATA_1: SR_DATA_0;
        cStrLib::DelayUs(5);
        SR_CLK_1;
        cStrLib::DelayUs(5);
        SR_CLK_0;

        --i;
    }
}


void cCounter::UpdateCounter()
{
    U16 valNgan     = s_CardCount % 10000;
    U16 valTram     = valNgan % 1000;
    U16 valChuc     = valTram % 100;

    ShiftLed(Led7SegDecode[valChuc % 10] | s_DpSetDv);
    ShiftLed(Led7SegDecode[valChuc / 10] | s_DpSetCh);
    ShiftLed(Led7SegDecode[valTram / 100] | s_DpSetTr);
    ShiftLed(Led7SegDecode[valNgan / 1000] | s_DpSetNg); 

    cStrLib::DelayUs(3);
    SR_STB_1;
    cStrLib::DelayUs(10);
    SR_STB_0;
}


bool cCounter::SetCounter(U16 iVal)
{
    if (10000 > iVal)
    {
        s_CardCount = iVal;
        //TODO: them phan luu vao NVRAM
        UpdateCounter();
        return (true);
    }
    return (false);
}


void cCounter::SetBeep(bool sc)
{
    if (true == sc)
    {
        s_BeepIsOn = true;
        s_BeepTick.ResetTimeBase();
        s_DpSetNg = DP_LED_SET;
        UpdateCounter();
    }
    else
    {
        s_BeepIsOn = false;
        s_DpSetNg = DP_LED_CLR;
        UpdateCounter();
    }
}

void cCounter::SetTimeZone(U8 iTpID, U16 iTimeZoneStart, U16 iTimeZoneEnd)
{
    s_pTimeZoneStart[iTpID & 0x0F] = iTimeZoneStart;
    s_pTimeZoneEnd[iTpID & 0x0F]   = iTimeZoneEnd;
    cConfig::SetTimeZone(s_pTimeZoneStart, s_pTimeZoneEnd);
}


U16 cCounter::GetTimeZone(U8 iTpID)
{
    //return (s_pTimeZone[iTpID & 0x0F]);
    return (0);
}


bool cCounter::IncCounter()
{
    if (10000 > s_CardCount)
    {
        s_CardCount++;
        UpdateCounter();
        return (true);
    }
    return (false);
}


void cCounter::UpdateTimeZone(U16 currMinute)
{
    s_TimeZoneStatus = 0;
    for (U8 i=0; i<cConfig::TIME_ZONE_MAX; i++)
    {
        if (0xFFFF != s_pTimeZoneStart[i] && 0xFFFF != s_pTimeZoneEnd[i])
        {
            if (s_pTimeZoneStart[i] <= currMinute && currMinute <= s_pTimeZoneEnd[i])
            {
                s_TimeZoneStatus |= 1<<i;
            }
        }
    }
}


U16 cCounter::GetTimeZoneStatus()
{
    return (s_TimeZoneStatus);
}


void cCounter::RunOne()
{
    if (true == s_NeedCheckTimePoint)
    {
        s_NeedCheckTimePoint = 0;

        U8 *pStrTime;
        U32 currMinute;

        pStrTime = cRtc::GetTimeAsStr();
        if (pStrTime[5] == 0)
        {
            currMinute = pStrTime[3]*60 + pStrTime[4];
            UpdateTimeZone(currMinute);
            if (s_TimeZoneStatus != s_TimeZoneStatusOld)
            {
                cUser::ResetUserReadMark();
                s_TimeZoneStatusOld = s_TimeZoneStatus;
            }

            SetCounter(pStrTime[3]*100 + pStrTime[4]);
        }
    }

    if (true == s_LedRedIsOn)
    {
        if (true == s_LedRedTick.CheckTimeOut())
        {
            SetLedRed(false);
        }
    }

    if (true == s_LedGreenIsOn)
    {
        if (true == s_LedGreenTick.CheckTimeOut())
        {
            SetLedGreen(false);
        }
    }

    if (true == s_BeepIsOn)
    {
        if (true == s_BeepTick.CheckTimeOut())
        {
            SetBeep(false);
        }
    }
}

